package Others.ExeclDataComparison;


import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Excel工具类：读取Excel文件数据并存储到Map集合，支持数据比较
 * 依赖：Apache POI 4.x/5.x（处理Excel文件）
 * Maven依赖配置：
 * <dependency>
 *     <groupId>org.apache.poi</groupId>
 *     <artifactId>poi</artifactId>
 *     <version>5.2.4</version>
 * </dependency>
 * <dependency>
 *     <groupId>org.apache.poi</groupId>
 *     <artifactId>poi-ooxml</artifactId>
 *     <version>5.2.4</version>
 * </dependency>
 */
public class ExcelToMapReader {

    /**
     * 读取Excel文件数据并存储到Map
     * @param filePath Excel文件路径（.xlsx格式）
     * @param keyColumnIndex 作为Map键的列索引（从0开始）
     * @param valueColumnIndex 作为Map值的列索引（从0开始）
     * @return 存储Excel数据的Map集合
     * @throws IOException 文件读取异常
     */
    public static Map<String, String> readExcelToMap(String filePath, int keyColumnIndex, int valueColumnIndex)
            throws IOException {
        Map<String, String> dataMap = new HashMap<>();
        FileInputStream fis = null;
        Workbook workbook = null;

        try {
            // 1. 创建文件输入流
            fis = new FileInputStream(filePath);
            // 2. 创建Excel工作簿（XSSFWorkbook支持.xlsx，HSSFWorkbook支持.xls）
            workbook = new XSSFWorkbook(fis);
            // 3. 获取第一个工作表（可根据工作表名称获取：workbook.getSheet("工作表名")）
            Sheet sheet = workbook.getSheetAt(0);

            // 4. 遍历工作表的行（跳过表头：从第1行开始，索引从0开始）
            for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
                Row row = sheet.getRow(rowNum);
                if (row == null) continue; // 跳过空行

                // 5. 获取指定列的单元格值
                Cell keyCell = row.getCell(keyColumnIndex);
                Cell valueCell = row.getCell(valueColumnIndex);

                // 6. 处理单元格数据（转换为字符串格式）
                String key = getCellValueAsString(keyCell);
                String value = getCellValueAsString(valueCell);

                // 7. 存入Map（若键重复，后面的值会覆盖前面的值）
                if (key != null && !key.isEmpty()) {
                    dataMap.put(key, value);
                }
            }

        } finally {
            // 8. 关闭资源（逆序：先关闭内层流）
            if (workbook != null) {
                workbook.close();
            }
            if (fis != null) {
                fis.close();
            }
        }

        return dataMap;
    }

    /**
     * 将Excel单元格值转换为字符串（处理不同数据类型）
     * @param cell Excel单元格对象
     * @return 单元格的字符串值（null返回空字符串）
     */
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }

        String cellValue = "";
        // 根据单元格类型处理数据
        switch (cell.getCellType()) {
            case STRING:
                cellValue = cell.getStringCellValue().trim();
                break;
            case NUMERIC:
                // 处理数字和日期类型
                if (DateUtil.isCellDateFormatted(cell)) {
                    cellValue = cell.getDateCellValue().toString().trim();
                } else {
                    // 数字类型避免科学计数法
                    cellValue = String.valueOf(cell.getNumericCellValue()).trim();
                    // 去除末尾的.0（如123.0 → 123）
                    if (cellValue.endsWith(".0")) {
                        cellValue = cellValue.substring(0, cellValue.lastIndexOf("."));
                    }
                }
                break;
            case BOOLEAN:
                cellValue = String.valueOf(cell.getBooleanCellValue()).trim();
                break;
            case FORMULA:
                // 公式单元格获取计算结果
                try {
                    cellValue = String.valueOf(cell.getNumericCellValue()).trim();
                } catch (IllegalStateException e) {
                    cellValue = cell.getStringCellValue().trim();
                }
                break;
            default:
                cellValue = "";
        }
        return cellValue;
    }

    /**
     * 示例：比较两个Map集合的数据差异
     * @param map1 第一个Map（源数据）
     * @param map2 第二个Map（目标数据）
     */
    public static void compareMapData(Map<String, String> map1, Map<String, String> map2) {
        System.out.println("=== 数据比较结果 ===");

//        // 1. 查找map1中有但map2中没有的键
//        System.out.println("\n1. map1独有的键：");
//        for (String key : map1.keySet()) {
//            if (!map2.containsKey(key)) {
//                System.out.printf("键：%s，值：%s%n", key, map1.get(key));
//            }
//        }
//
//        System.out.println();
//        System.out.println();
//
//        // 2. 查找map2中有但map1中没有的键
//        System.out.println("\n2. map2独有的键：");
//        for (String key : map2.keySet()) {
//            if (!map1.containsKey(key)) {
//                System.out.printf("键：%s，值：%s%n", key, map2.get(key));
//            }
//        }
//
//        System.out.println();
//        System.out.println();

        // 3. 查找键相同但值不同的数据
        System.out.println("\n3. 键相同但值不同的数据：");
        for (String key : map1.keySet()) {
            if (map2.containsKey(key)) {
                String value1 = map1.get(key);
                String value2 = map2.get(key);
                if (!value1.equals(value2)) {
                    System.out.printf("键：%s，报表：%s，数据库：%s%n", key, value1, value2);
                }
            }
        }
    }

    // 主方法：测试示例
    //比较两个Excel文件的数据内容差异--Excel格式为-->key,value(E1)    key,value(E2)
    //                                          aaa,123          aaa,123
    //                                          bbb,456          ccc,123
    //比较像这种格式的Excel文件数据是否一致，并且将不一致的数据输出
    public static void main(String[] args) {
        try {
            // 1. 读取第一个Excel文件（键：第0列，值：第1列）
            String excelPath1 = "C:\\Users\\Administrator\\Desktop\\文件.xlsx";
            Map<String, String> dataMap1 = readExcelToMap(excelPath1, 0, 1);
            System.out.println("读取Excel1数据量：" + dataMap1.size());

            // 2. 读取第二个Excel文件（用于比较，可替换为其他数据源）
            String excelPath2 = "C:\\Users\\Administrator\\Desktop\\数据库.xlsx";
            Map<String, String> dataMap2 = readExcelToMap(excelPath2, 0, 1);
            System.out.println("读取Excel2数据量：" + dataMap2.size());

            // 3. 比较两个Map的数据差异
            compareMapData(dataMap1, dataMap2);

        } catch (IOException e) {
            System.err.println("文件读取失败：" + e.getMessage());
            e.printStackTrace();
        }
    }
}
